package sintactica;

import analizator.Analizator.Atom;
import analizator.CuvantCheie.Keyword;
import analizator.*;
import java.util.ArrayList;
import sintactica.Simbol.ClsSimbol;
import sintactica.Simbol.TipSimbol;
import sintactica.Tip.TipValue;

/**
 * ES -> TS | ES + TS ; ES -> TS ES2; ES2 -> + TS ES2 | Epsilon
 *
 * @author bufu
 */
public class AnalizatorSintactic {

    private AtomProvider m_provider;
    private boolean debug = true;
    private boolean debugExceptions = true;
    private boolean debugNereusite = false;
    private boolean debugTabelaSimbol = true;
    private int m_nNivel = 0;
    private int tab = 0;
    private TabelaSimbol m_tblSimbol;
    private Deplasare m_depStruct;
    private Deplasare m_depVar;
    private ArrayList<Integer> m_IdenificatoriRecord;

    public AnalizatorSintactic(AtomProvider provider) {
        m_provider = provider;
        m_tblSimbol = new TabelaSimbol();
        m_depStruct = new Deplasare();
        m_depVar = new Deplasare();
        //printTabelaSimboluri();
    }

    private void printTabelaSimboluri() {
        m_tblSimbol.printTabelaSimboluri();
    }

    private void debugTabelaSimboluri() {
        if (debugTabelaSimbol) {
            printTabelaSimboluri();
        }
    }

    private void printDebug(String message) {
        if (debug) {
            System.out.print(tab);
            for (int i = 0; i < tab; i++) {
                System.out.print("  ");
            }
            System.out.println(message);
        }
    }

    private void printNereusit(String message) {
        if (debugNereusite) {
            System.out.println("nereusit:" + message);
        }
    }

    private void debugException(AsinException e) {
        if (debugExceptions) {
            e.printStackTrace(System.out);
        }
    }

    private void makeProgram() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        m_nNivel = 1;
        printDebug("makeProgram");
        Atom program = m_provider.debugGetNextAtom();
        if (!checkKeyword(program, Keyword.PROGRAM)) {
            m_provider.revertOne();
            throw new AsinException("program not found");
        }
        Atom iden = m_provider.debugGetNextAtom();
        if (checkIdentifier(iden) == null) {
            m_provider.setIndex(index);
            throw new AsinException("no identificator");
        }
        Atom delimitator = m_provider.debugGetNextAtom();
        if (!checkDelimitator(delimitator, ";")) {
            m_provider.setIndex(index);
            throw new AsinException("no ;");
        }
        tab = t;
        makeBloc();
        Atom delimitator2 = m_provider.debugGetNextAtom();
        if (!checkDelimitator(delimitator2, ".")) {
            m_provider.setIndex(index);
            throw new AsinException("no .");
        }
    }

    private void makeBloc() throws AsinException {
        int t = ++tab;
        printDebug("makeBloc");
        makeSectiuneConst();
        tab = t;
        makeSectiuneVar();
        tab = t;
        makeSectiuneDeclSubprog();
        tab = t;
        makeInstrComp();
    }

    private void makeSectiuneConst() throws AsinException {
        int t = ++tab;
        printDebug("makeSectiuneConst");
        Atom constanta = m_provider.debugGetNextAtom();
        if (!checkKeyword(constanta, Keyword.CONST)) {
            m_provider.putUnusedAtom(constanta);
        } else {
            makeListaDeclConst();
        }
    }

    private void makeListaDeclConst() throws AsinException {
        int t = ++tab;
        printDebug("makeListaDeclConst");
        makeDeclarConst();
        tab = t;
        makeListaDeclConst2();
    }

    private void makeListaDeclConst2() throws AsinException {
        int t = ++tab;
        printDebug("makeListaDeclConst2");
        try {
            while (true) {
                tab = t;
                makeDeclarConst();
            }
        } catch (AsinException e) {
            tab = t;
            debugException(e);
            printNereusit("makeListaDeclConst2");
        }
    }

    private void makeDeclarConst() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeDeclarConst");
        Atom iden = m_provider.debugGetNextAtom();
        String numeIden = checkIdentifier(iden);
        if (numeIden == null) {
            m_provider.setIndex(index);
            throw new AsinException("makeDeclarConst:no identificator");
        }
        Atom egal = m_provider.debugGetNextAtom();
        if (!checkOperator(egal, "=")) {
            m_provider.setIndex(index);
            throw new AsinException("no =");
        }
        tab = t;
        Tip tValoare = makeExpresieStatica();
        Atom delimitator = m_provider.debugGetNextAtom();
        if (!checkDelimitator(delimitator, ";")) {
            m_provider.setIndex(index);
            throw new AsinException("no ;");
        }
        insertConstanta(numeIden, tValoare);
    }

    private void insertConstanta(String numeIden, Tip tValoare) {
        Simbol sConstanta = new Simbol();
        sConstanta.clasa = ClsSimbol.CONSTANTA;
        sConstanta.nume = numeIden;
        sConstanta.nivel = m_nNivel;
        m_tblSimbol.addConstanta(sConstanta, tValoare);
        debugTabelaSimboluri();
    }

    private Tip makeExpresieStatica() throws AsinException {
        int t = ++tab;
        printDebug("makeExpresieStatica");
        Tip tipTermen = makeTermenStatic();
        tab = t;
        return makeExpresieStatica2(tipTermen);
    }

    private Tip makeTermenStatic() throws AsinException {
        int t = ++tab;
        printDebug("makeTermenStatic");
        Tip tFactor = makeFactorStatic();
        tab = t;
        return makeTermenStatic2(tFactor);
    }

    private Tip makeFactorStatic() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeFactorStatic");

        Atom a = m_provider.debugGetNextAtom();
        String nume = checkIdentifier(a);
        if (nume != null) {
            Tip tConstanta = m_tblSimbol.hasConstanta(nume);
            if (tConstanta == null) {
                throw new AsinException("nu se gaseste constanta");
            }
            return tConstanta;
        } else {
            m_provider.setIndex(index);
        }
        Tip tConst = null;
        try {
            tab = t;
            tConst = makeConstanta();
        } catch (AsinException ex) {
            debugException(ex);
        }
        if (tConst != null) {
            return tConst;
        }
        Atom del = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del, "(")) {
            m_provider.setIndex(index);
            throw new AsinException("no possibility");
        }
        tab = t;
        tConst = makeExpresieStatica();
        Atom del2 = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del2, ")")) {
            m_provider.setIndex(index);
            throw new AsinException("no )");
        }
        return tConst;
    }

    private Tip makeConstanta() throws AsinException {
        int t = ++tab;
        printDebug("makeConstanta");

        Atom a = m_provider.debugGetNextAtom();
        Tip tConst;
        if (a instanceof NumarIntreg) {
            tConst = new Tip();
            tConst.tip = TipSimbol.INT;
            tConst.valoare = ((NumarIntreg) a).m_value;
            tConst.lvalue = TipValue.VALOARE;
            return tConst;
        }
        if (a instanceof NumarReal) {
            tConst = new Tip();
            tConst.tip = TipSimbol.REAL;
            tConst.valoare = ((NumarReal) a).m_value;
            tConst.lvalue = TipValue.VALOARE;
            return tConst;
        }
        if (a instanceof ConstChar) {
            tConst = new Tip();
            tConst.tip = TipSimbol.CHAR;
            tConst.valoare = ((ConstChar) a).m_value;
            tConst.lvalue = TipValue.VALOARE;
            return tConst;
        }
        m_provider.revertOne();
        throw new AsinException("can't make constanta");
    }

    private Tip makeTermenStatic2(Tip tTermen) throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeTermenStatic2 cu tip " + tTermen.tip);

        OpMul operatie;
        try {
            tab = t;
            operatie = makeOpMul();
        } catch (Exception ex) {
            printNereusit("nu am gasit operatie mul");
            return tTermen;
        }
        Tip tCurent;
        try {
            tab = t;
            tCurent = makeFactorStatic();
        } catch (AsinException ex) {
            debugException(ex);
            m_provider.setIndex(index);
            throw new AsinException("nu am gasit factor static,ultima op " + operatie);
        }
        tab = t;
        Tip tRez = new Tip();
        if (operatie == OpMul.DIV || operatie == OpMul.MOD) {
            if (tTermen.tip != TipSimbol.INT || tCurent.tip != TipSimbol.INT) {
                throw new AsinException("Tipuri incompatibile pentru div/mod!");
            }
            tRez.tip = TipSimbol.INT;
        } else {
            if (tTermen.tip == TipSimbol.CHAR || tCurent.tip == TipSimbol.CHAR) {
                throw new AsinException("Tipuri incompatibile pentru * /!");
            }
            if (operatie == OpMul.MULTIPLY
                    && tTermen.tip == TipSimbol.INT && tCurent.tip == TipSimbol.INT) {
                tRez.tip = TipSimbol.INT;
            } else {
                tRez.tip = TipSimbol.REAL;
            }
        }

        return makeTermenStatic2(tRez);
    }

    private Tip makeExpresieStatica2(Tip tPrevious) throws AsinException {
        int t = ++tab;
        printDebug("makeExpresieStatica2");

        Atom atoms;
        try {
            tab = t;
            atoms = makeOpAd();
        } catch (Exception ex) {
            printNereusit("nu am gasit operatie ad");
            return tPrevious;
        }
        Tip tTermenNou;
        try {
            tab = t;
            tTermenNou = makeTermenStatic();
        } catch (Exception ex) {
            m_provider.putUnusedAtom(atoms);
            throw new AsinException("no next static termen!");
        }
        Tip tRez = new Tip();
        if (tPrevious.tip == TipSimbol.CHAR || tTermenNou.tip == TipSimbol.CHAR) {
            throw new AsinException("Nu se pot +/- caractere!");
        }
        if (tPrevious.tip == TipSimbol.INT && tTermenNou.tip == TipSimbol.INT) {
            tRez.tip = TipSimbol.INT;
        } else {
            tRez.tip = TipSimbol.REAL;
        }

        return makeExpresieStatica2(tRez);
    }

    private Atom makeOpAd() throws AsinException {
        int t = ++tab;
        printDebug("makeOperatieAd");

        Atom a = m_provider.debugGetNextAtom();
        if (a instanceof Operator) {
            Operator o = (Operator) a;
            if (o.m_value.equals("+") || o.m_value.equals("-")) {
                return a;
            }
        }
        m_provider.putUnusedAtom(a);
        throw new AsinException("no + or -");

    }

    private OpMul makeOpMul() throws AsinException {
        int t = ++tab;
        printDebug("makeOperatieMul");

        Atom a = m_provider.debugGetNextAtom();
        if (a instanceof Operator) {
            Operator o = (Operator) a;
            if (o.m_value.equals("*")) {
                return OpMul.MULTIPLY;
            }
            if (o.m_value.equals("/")) {
                return OpMul.DIVIDE;
            }
        }
        if (checkKeyword(a, Keyword.DIV)) {
            return OpMul.DIV;
        }
        if (checkKeyword(a, Keyword.MOD)) {
            return OpMul.MOD;
        }
        m_provider.revertOne();
        throw new AsinException("no multiplication operator");
    }

    private void makeSectiuneVar() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeSectiuneVar");
        m_depVar.seteaza();
        Atom constanta = m_provider.debugGetNextAtom();
        if (!checkKeyword(constanta, Keyword.VAR)) {
            m_provider.setIndex(index);
        } else {
            tab = t;
            makeListaDeclVar();
        }
    }

    private void makeListaDeclVar() throws AsinException {
        int t = ++tab;
        printDebug("makeListaDeclVar");

        makeDeclarVar();
        tab = t;
        makeListaDeclVar2();
    }

    private void makeListaDeclVar2() throws AsinException {
        int t = ++tab;
        printDebug("makeListaDeclVar2");

        try {
            while (true) {
                tab = t;
                makeDeclarVar();
            }
        } catch (AsinException e) {
            debugException(e);
        }
    }

    private void makeDeclarVar() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeDeclarVar");

        ArrayList<Simbol> lista = makeListaId();
        Atom delim = m_provider.debugGetNextAtom();
        if (!checkDelimitator(delim, ":")) {
            m_provider.setIndex(index);
            throw new AsinException("no :");
        }
        tab = t;
        makeTip(lista);
        Atom delim2 = m_provider.debugGetNextAtom();
        if (!checkDelimitator(delim2, ";")) {
            m_provider.setIndex(index);
            throw new AsinException("no ;");
        }
    }

    private void makeTip(ArrayList<Simbol> lista) throws AsinException {
        int t = ++tab;
        printDebug("makeTip");

        boolean found = true;
        try {
            tab = t;
            TipSimbol tip = makeTipSimplu();
            for (Simbol s : lista) {
                s.tip = tip;
                s.adrel = m_depVar.get();
                m_depVar.mareste(1);
            }

        } catch (AsinException e) {
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeTipTablou(lista);
        } catch (AsinException e) {
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeTipStruct(lista);
        } catch (AsinException e) {
            debugException(e);
            found = false;
        }
        if (!found) {
            throw new AsinException("cannot create tip");
        }
    }

    private TipSimbol makeTipSimplu() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeTipSimplu");

        Atom a = m_provider.debugGetNextAtom();
        if (checkKeyword(a, Keyword.INTEGER)) {
            return TipSimbol.INT;
        } else if (checkKeyword(a, Keyword.REAL)) {
            return TipSimbol.REAL;
        } else if (checkKeyword(a, Keyword.CHAR)) {
            return TipSimbol.CHAR;
        }
        m_provider.setIndex(index);
        throw new AsinException("cannot make tip simplu");
    }

    private void makeTipTablou(ArrayList<Simbol> lista) throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeTipTablou");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.ARRAY)) {
            m_provider.setIndex(index);
            throw new AsinException("cannot make tip simplu");
        }
        Atom o = m_provider.debugGetNextAtom();
        if (!checkOperator(o, "[")) {
            m_provider.setIndex(index);
            throw new AsinException("cannot make tip simplu 2");
        }
        tab = t;
        makeExpresieStatica();
        Atom op = m_provider.debugGetNextAtom();
        if (!checkDelimitator(op, "..")) {
            m_provider.setIndex(index);
            throw new AsinException("cannot make tip simplu 3");
        }
        tab = t;
        makeExpresieStatica();
        Atom o2 = m_provider.debugGetNextAtom();
        if (!checkOperator(o2, "]")) {
            m_provider.setIndex(index);
            throw new AsinException("cannot make tip simplu 4");
        }
        Atom a2 = m_provider.debugGetNextAtom();
        if (!checkKeyword(a2, Keyword.OF)) {
            m_provider.setIndex(index);
            throw new AsinException("cannot make tip simplu 5");
        }
        tab = t;
        TipSimbol tip = makeTipSimplu();
        for (Simbol s : lista) {
            s.clasa = ClsSimbol.TABLOU;
            s.tip = tip;
            s.ind_min = 2;
            s.ind_max = 10;
            s.adrel = m_depVar.get();
            m_depVar.mareste(8);
        }
    }

    private void makeTipStruct(ArrayList<Simbol> lista) throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeTipStruct");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.RECORD)) {
            m_provider.setIndex(index);
            throw new AsinException("cannot make tip struct");
        }
        tab = t;
        m_depStruct.seteaza();
        m_IdenificatoriRecord = new ArrayList<>();
        for (Simbol s : lista) {
            m_IdenificatoriRecord.add(m_tblSimbol.getIndex(s));
        }
        makeListaCamp();
        Atom a2 = m_provider.debugGetNextAtom();
        if (!checkKeyword(a2, Keyword.END)) {
            m_provider.setIndex(index);
            throw new AsinException("cannot make tip struct 2");
        }
        for (Simbol s : lista) {
            s.clasa = ClsSimbol.STRUCT;
            s.adrel = m_depVar.get();
            m_depVar.mareste(m_depStruct.get());
        }
    }

    private void makeListaCamp() throws AsinException {
        int t = ++tab;
        printDebug("makeListaCamp");

        makeDeclSimpla(ClsSimbol.CAMP_STRUCT);
        tab = t;
        makeListaCamp2();
    }

    private ArrayList<Simbol> makeDeclSimpla(ClsSimbol clasa) throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeDeclSimpla");
        tab = t;
        ArrayList<Simbol> lista = makeListaId();
        Atom a = m_provider.debugGetNextAtom();
        if (!checkDelimitator(a, ":")) {
            m_provider.setIndex(index);
            throw new AsinException("cannot find :");
        }
        tab = t;
        TipSimbol tip = makeTipSimplu();
        for (Simbol s : lista) {
            s.clasa = clasa;
            s.tip = tip;
            if (clasa == ClsSimbol.CAMP_STRUCT) {
                s.deplrel = m_depStruct.get();
                m_depStruct.mareste(1);
                s.lista_rec = m_IdenificatoriRecord;
            } else {
                s.adrel = m_depVar.get();
                m_depVar.mareste(1);
            }
        }
        return lista;
    }

    private void makeListaCamp2() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeListaCamp2");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkDelimitator(a, ";")) {
            m_provider.setIndex(index);
            return;
        }
        try {
            tab = t;
            makeDeclSimpla(ClsSimbol.CAMP_STRUCT);
        } catch (AsinException ex) {
            m_provider.setIndex(index);
            debugException(ex);
            return;
        }
        try {
            tab = t;
            makeListaCamp2();
        } catch (AsinException ex) {
            debugException(ex);
        }
    }

    private ArrayList<Simbol> makeListaId() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        ArrayList<Simbol> lista = new ArrayList<>();
        printDebug("makeListaId");

        Atom a = m_provider.debugGetNextAtom();
        String numeIden = checkIdentifier(a);
        if (numeIden == null) {
            m_provider.setIndex(index);
            throw new AsinException("no identificator");
        }
        lista.add(insertListaId(numeIden));
        tab = t;
        lista.addAll(makeListaId2());
        return lista;
    }

    private Simbol insertListaId(String identifier) {
        Simbol sConstanta = new Simbol();
        sConstanta.clasa = ClsSimbol.VARIABILA;
        sConstanta.nume = identifier;
        sConstanta.nivel = m_nNivel;
        m_tblSimbol.addSimbol(sConstanta);
        debugTabelaSimboluri();
        return sConstanta;
    }

    private ArrayList<Simbol> makeListaId2() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        ArrayList<Simbol> lista = new ArrayList<>();
        printDebug("makeListaId2");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkDelimitator(a, ",")) {
            m_provider.setIndex(index);
            tab = t;
            return lista;
        }
        Atom iden = m_provider.debugGetNextAtom();
        String numeIden = checkIdentifier(iden);
        if (numeIden == null) {
            tab = t;
            throw new AsinException("no identificator");
        }
        lista.add(insertListaId(numeIden));
        lista.addAll(makeListaId2());
        tab = t;
        return lista;
    }

    private void makeSectiuneDeclSubprog() throws AsinException {
        int t = ++tab;
        printDebug("makeSectiuneDeclSubprog");

        try {
            tab = t;
            makeListaDeclSubprog();
        } catch (AsinException e) {
            debugException(e);
        }
    }

    private void makeListaDeclSubprog() throws AsinException {
        int t = ++tab;
        printDebug("makeListaDeclSubprog");

        makeDeclSubprog();
        tab = t;
        makeListaDeclSubprog2();
    }

    private void makeDeclSubprog() throws AsinException {
        int t = ++tab;
        int level = m_nNivel++;
        printDebug("makeDeclSubprog");

        boolean found = true;
        try {
            tab = t;
            makeDeclarFunctie();
        } catch (AsinException e) {
            debugException(e);
            found = false;
        }
        if (found) {
            m_nNivel = level;
            return;
        }
        found = true;
        try {
            tab = t;
            makeDeclarProcedura();
        } catch (AsinException e) {
            debugException(e);
            found = false;
        }
        m_nNivel = level;
        if (!found) {
            throw new AsinException("can't make decl subprog");
        }
    }

    private void makeDeclarProcedura() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeDeclarProcedura");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.PROCEDURE)) {
            m_provider.setIndex(index);
            throw new AsinException("no procedure");
        }
        tab = t;
        Simbol sProcedura = makeAntetSubprog(ClsSimbol.PROCEDURA);
        Atom del2 = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del2, ";")) {
            m_provider.setIndex(index);
            throw new AsinException("no ;");
        }
        tab = t;
        makeBloc();
        sProcedura.dim_var = m_depVar.get();
        m_depVar.seteaza();
        Atom del3 = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del3, ";")) {
            m_provider.setIndex(index);
            throw new AsinException("no ; 2");
        }
    }

    private void makeDeclarFunctie() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeDeclarFunctie");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.FUNCTION)) {
            m_provider.setIndex(index);
            throw new AsinException("no function");
        }
        tab = t;
        Simbol sFunctie = makeAntetSubprog(ClsSimbol.FUNCTIE);
        Atom del = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del, ":")) {
            m_provider.setIndex(index);
            throw new AsinException("no :");
        }
        tab = t;
        TipSimbol tip = makeTipSimplu();
        sFunctie.tip = tip;

        Atom del2 = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del2, ";")) {
            m_provider.setIndex(index);
            throw new AsinException("no ;");
        }
        tab = t;
        makeBloc();
        sFunctie.dim_var = m_depVar.get();
        m_depVar.seteaza();
        Atom del3 = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del3, ";")) {
            m_provider.setIndex(index);
            throw new AsinException("no ; 2");
        }
        m_tblSimbol.clearLevel(m_nNivel);
    }

    private Simbol makeAntetSubprog(ClsSimbol clasa) throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeAntetSubprog");

        Atom a = m_provider.debugGetNextAtom();
        String numeIden = checkIdentifier(a);
        if (numeIden == null) {
            m_provider.setIndex(index);
            throw new AsinException("no identifier");
        }
        Simbol sFunctie = new Simbol();
        sFunctie.clasa = clasa;
        sFunctie.nivel = m_nNivel - 1;
        sFunctie.adrel = -1;
        sFunctie.adr_start = -1;
        if (a instanceof Identificator) {
            sFunctie.nume = ((Identificator) a).getNume();
        } else {
            sFunctie.nume = ((Caracter) a).value + "";
        }
        m_tblSimbol.addSimbol(sFunctie);
        debugTabelaSimboluri();
        tab = t;
        ArrayList<Simbol> listaParam = makeParamForm();
        sFunctie.nr_par = listaParam.size();
        ArrayList<Integer> listaIndPar = new ArrayList<>();
        for (Simbol s : listaParam) {
            listaIndPar.add(m_tblSimbol.getIndex(s));
        }
        sFunctie.lista_par = listaIndPar;
        return sFunctie;
    }

    private ArrayList<Simbol> makeParamForm() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeParamForm");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkOperator(a, "(")) {
            m_provider.setIndex(index);
            return new ArrayList<>();
        }
        tab = t;
        ArrayList<Simbol> lista = makeListaParamForm();
        Atom a2 = m_provider.debugGetNextAtom();
        if (!checkOperator(a2, ")")) {
            m_provider.setIndex(index);
            throw new AsinException("no )");
        }
        return lista;
    }

    private ArrayList<Simbol> makeListaParamForm() throws AsinException {
        int t = ++tab;
        printDebug("makeListaParamForm");
        m_depVar.seteaza();
        ArrayList<Simbol> lista = makeDeclarPar();
        tab = t;
        lista.addAll(
                makeListaParamForm2());
        return lista;
    }

    private ArrayList<Simbol> makeDeclarPar() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeDeclarPar");
        ClsSimbol clasa;
        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.VAR)) {
            m_provider.setIndex(index);
            clasa = ClsSimbol.CAMP_PARA;
        } else {
            clasa = ClsSimbol.CAMP_PARA_REF;
        }
        tab = t;
        return makeDeclSimpla(clasa);
    }

    private ArrayList<Simbol> makeListaParamForm2() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeListaParamForm2");

        Atom del = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del, ";")) {
            m_provider.setIndex(index);
            return new ArrayList<>();
        }
        tab = t;
        ArrayList<Simbol> lista = makeDeclarPar();
        tab = t;
        lista.addAll(makeListaParamForm2());
        return lista;
    }

    private void makeListaDeclSubprog2() throws AsinException {
        int t = ++tab;
        printDebug("makeListaDeclSubprog2");

        try {
            tab = t;
            makeDeclSubprog();
        } catch (Exception e) {
            printNereusit("makeListaDeclSubprog2");
            return;
        }
        tab = t;
        makeListaDeclSubprog2();
    }

    private void makeInstrComp() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeInstrComp");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.BEGIN)) {
            m_provider.setIndex(index);
            throw new AsinException("no begin");
        }
        tab = t;
        makeListaInstr();
        Atom del = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del, ";")) {
            m_provider.revertOne();
        }
        Atom a2 = m_provider.debugGetNextAtom();
        if (!checkKeyword(a2, Keyword.END)) {
            m_provider.setIndex(index);
            throw new AsinException("no end");
        }
    }

    private void makeListaInstr() throws AsinException {
        int t = ++tab;
        printDebug("makeListaInstr");

        makeInstr();
        tab = t;
        makeListaInstr2();
    }

    private void makeInstr() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeInstr");

        boolean found = true;
        try {
            tab = t;
            makeInstrAtrib();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeInstrIf();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeInstrWhile();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeInstrRepeat();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeInstrFor();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeInstrCase();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeInstrComp();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeApelProc();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeInstrRead();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (found) {
            return;
        }
        found = true;
        try {
            tab = t;
            makeInstrPrint();
        } catch (AsinException e) {
            debugException(e);
            m_provider.setIndex(index);
            found = false;
        }
        if (!found) {
            throw new AsinException("no possibility");
        }
    }

    private void makeInstrPrint() throws AsinException {
        int t = ++tab;
        printDebug("makeInstrPrint");

        Atom o = m_provider.debugGetNextAtom();
        if (!checkKeyword(o, Keyword.PRINT)) {
            m_provider.putUnusedAtom(o);
            throw new AsinException("no print");
        }
        Atom a = m_provider.debugGetNextAtom();
        if (!checkOperator(a, "(")) {
            m_provider.putUnusedAtom(a);
            m_provider.putUnusedAtom(o);
            throw new AsinException("no (");
        }
        tab = t;
        makeListaElem();
        Atom a2 = m_provider.debugGetNextAtom();
        if (!checkOperator(a2, ")")) {
            m_provider.putUnusedAtom(a2);
            throw new AsinException("no )");
        }
    }

    private void makeListaElem() throws AsinException {
        int t = ++tab;
        printDebug("makeListaElem");

        makeElement();
        tab = t;
        makeListaElement2();
    }

    private void makeListaElement2() throws AsinException {
        int t = ++tab;
        printDebug("makeListaElement2");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkDelimitator(a, ",")) {
            m_provider.putUnusedAtom(a);
            return;
        }
        makeElement();
        tab = t;
        makeListaElement2();
    }

    private void makeElement() throws AsinException {
        int t = ++tab;
        printDebug("makeElement");

        Atom a = m_provider.debugGetNextAtom();
        if (a instanceof Sir) {
            return;
        }
        m_provider.putUnusedAtom(a);
        tab = t;
        makeExpresie();
    }

    private void makeInstrRead() throws AsinException {
        int t = ++tab;
        printDebug("makeInstrRead");

        Atom o = m_provider.debugGetNextAtom();
        if (!checkKeyword(o, Keyword.READ)) {
            m_provider.putUnusedAtom(o);
            throw new AsinException("no read");
        }
        Atom a = m_provider.debugGetNextAtom();
        if (!checkOperator(a, "(")) {
            m_provider.putUnusedAtom(a);
            m_provider.putUnusedAtom(o);
            throw new AsinException("no (");
        }
        tab = t;
        makeListaVariab();
        Atom a2 = m_provider.debugGetNextAtom();
        if (!checkOperator(a2, ")")) {
            m_provider.putUnusedAtom(a2);
            throw new AsinException("no )");
        }
    }

    private void makeListaVariab() throws AsinException {
        int t = ++tab;
        printDebug("makeListaVariab");

        makeVariabila();
        tab = t;
        makeListaVariab2();
    }

    private void makeListaVariab2() throws AsinException {
        int t = ++tab;
        printDebug("makeListaVariab2");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkDelimitator(a, ",")) {
            m_provider.putUnusedAtom(a);
            return;
        }
        tab = t;
        makeVariabila();
        tab = t;
        makeListaVariab2();
    }

    private void makeApelProc() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeApelProc");

        Atom o = m_provider.debugGetNextAtom();
        String numeIden = checkIdentifier(o);
        if (numeIden == null) {
            m_provider.setIndex(index);
            throw new AsinException("no identifier");
        }
        Atom a = m_provider.debugGetNextAtom();
        if (!checkOperator(a, "(")) {
            m_provider.revertOne();
            return;
        }
        tab = t;
        makeListaExpresii();
        Atom a2 = m_provider.debugGetNextAtom();
        if (!checkOperator(a2, ")")) {
            m_provider.setIndex(index);
            throw new AsinException("no )");
        }

    }

    private void makeInstrCase() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeInstrCase");

        Atom o = m_provider.debugGetNextAtom();
        if (!checkKeyword(o, Keyword.CASE)) {
            m_provider.revertOne();
            throw new AsinException("no case");
        }
        tab = t;
        makeExpresie();
        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.OF)) {
            m_provider.setIndex(index);
            throw new AsinException("no of");
        }
        tab = t;
        makeListaAltern();
        Atom a2 = m_provider.debugGetNextAtom();
        if (!checkKeyword(a2, Keyword.END)) {
            m_provider.setIndex(index);
            throw new AsinException("no end");
        }
    }

    private void makeListaAltern() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeListaAltern");
        tab = t;
        makeListaRamuri();
        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.OTHERWISE)) {
            m_provider.revertOne();
            throw new AsinException("no otherwise");
        }
        Atom del = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del, ":")) {
            m_provider.setIndex(index);
            throw new AsinException("no :");
        }
        tab = t;
        makeInstr();
    }

    private void makeListaRamuri() throws AsinException {
        int t = ++tab;
        printDebug("makeListaRamuri");
        tab = t;
        makeRamura();
        tab = t;
        makeListaRamuri2();
    }

    private void makeListaRamuri2() throws AsinException {
        int t = ++tab;
        printDebug("makeListaRamuri2");

        try {
            tab = t;
            makeRamura();
        } catch (AsinException e) {
            return;
        }
        tab = t;
        makeListaRamuri2();
    }

    private void makeRamura() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeRamura");
        tab = t;
        makeListaVal();
        Atom del = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del, ":")) {
            m_provider.revertOne();
            throw new AsinException("no :");
        }
        tab = t;
        makeInstr();
        Atom del2 = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del2, ";")) {
            m_provider.setIndex(index);
            throw new AsinException("no ;");
        }
    }

    private void makeListaVal() throws AsinException {
        int t = ++tab;
        printDebug("makeListaVal");
        tab = t;
        makeConstanta();
        tab = t;
        makeListaVal2();
    }

    private void makeListaVal2() throws AsinException {
        int t = ++tab;
        printDebug("makeListaVal2");

        Atom del = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del, ",")) {
            m_provider.revertOne();
            return;
        }
        tab = t;
        makeConstanta();
        tab = t;
        makeListaVal2();
    }

    private void makeInstrFor() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeInstrFor");

        Atom o = m_provider.debugGetNextAtom();
        if (!checkKeyword(o, Keyword.FOR)) {
            m_provider.setIndex(index);
            throw new AsinException("no for");
        }
        tab = t;
        Tip tVariabila = makeVariabila();
        if (tVariabila.lvalue != TipValue.ADRESA) {
            throw new AsinException("Variabila nu e de tip adresa!");
        }
        if (tVariabila.tip != TipSimbol.INT) {
            throw new AsinException("Variabila de tip diferit de int!");
        }
        Atom a = m_provider.debugGetNextAtom();
        if (!checkOperator(a, ":=")) {
            m_provider.setIndex(index);
            throw new AsinException("no :=");
        }
        tab = t;
        Tip tStart = makeExpresie();
        if (tStart.tip != TipSimbol.INT) {
            throw new AsinException("Start diferit de int!");
        }
        tab = t;
        makeSens();
        tab = t;
        Tip tStop = makeExpresie();
        if (tStop.tip != TipSimbol.INT) {
            throw new AsinException("End diferit de int");
        }
        tab = t;
        Tip tPas = makePas();
        if (tPas.tip != TipSimbol.INT) {
            throw new AsinException("Tip pas not int!");
        }
        Atom a2 = m_provider.debugGetNextAtom();
        if (!checkKeyword(a2, Keyword.DO)) {
            m_provider.setIndex(index);
            throw new AsinException("no do");
        }
        tab = t;
        makeInstr();
    }

    private Tip makePas() throws AsinException {
        int t = ++tab;
        printDebug("makePas");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.STEP)) {
            m_provider.revertOne();
            Tip tPas = new Tip();
            tPas.tip = TipSimbol.INT;
            tPas.valoare = 1;
            tPas.lvalue = TipValue.VALOARE;
            return tPas;
        }
        tab = t;
        return makeExpresie();
    }

    private void makeSens() throws AsinException {
        int t = ++tab;
        printDebug("makeSens");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.TO) && !checkKeyword(a, Keyword.DOWNTO)) {
            m_provider.putUnusedAtom(a);
            throw new AsinException("no to or downto");
        }
    }

    private void makeInstrRepeat() throws AsinException {
        int t = ++tab;
        printDebug("makeInstrRepeat");

        Atom o = m_provider.debugGetNextAtom();
        if (!checkKeyword(o, Keyword.REPEAT)) {
            m_provider.putUnusedAtom(o);
            throw new AsinException("no repeat");
        }
        tab = t;
        makeInstr();
        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.UNTIL)) {
            m_provider.putUnusedAtom(a);
            throw new AsinException("no until");
        }
        tab = t;
        makeConditie();
    }

    private void makeInstrWhile() throws AsinException {
        int t = ++tab;
        printDebug("makeInstrWhile");

        Atom o = m_provider.debugGetNextAtom();
        if (!checkKeyword(o, Keyword.WHILE)) {
            m_provider.putUnusedAtom(o);
            throw new AsinException("no while");
        }
        tab = t;
        makeConditie();
        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.DO)) {
            m_provider.putUnusedAtom(a);
            throw new AsinException("no do");
        }
        tab = t;
        makeInstr();
    }

    private void makeInstrIf() throws AsinException {
        int t = ++tab;
        printDebug("makeInstrIf");

        Atom o = m_provider.debugGetNextAtom();
        if (!checkKeyword(o, Keyword.IF)) {
            m_provider.putUnusedAtom(o);
            throw new AsinException("no if");
        }
        tab = t;
        makeConditie();
        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.THEN)) {
            m_provider.putUnusedAtom(a);
            throw new AsinException("no thenF");
        }
        tab = t;
        makeInstr();
        tab = t;
        makeRamuraElse();
    }

    private void makeRamuraElse() throws AsinException {
        int t = ++tab;
        printDebug("makeRamuraElse");

        Atom a = m_provider.debugGetNextAtom();
        if (!checkKeyword(a, Keyword.ELSE)) {
            m_provider.putUnusedAtom(a);
            return;
        }
        tab = t;
        makeInstr();
    }

    private void makeConditie() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeConditie");
        Atom o = m_provider.debugGetNextAtom();
        if (!checkKeyword(o, Keyword.NOT)) {
            m_provider.revertOne();
        }
        tab = t;
        makeExprLogica();
    }

    private void makeExprLogica() throws AsinException {
        int t = ++tab;
        printDebug("makeExprLogica");
        tab = t;
        makeExprRel();
        tab = t;
        makeExprLogica2();
    }

    private void makeExprRel() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeExprRel");

        Atom o = m_provider.debugGetNextAtom();
        if (checkOperator(o, "(")) {
            tab = t;
            makeConditie();
            Atom a = m_provider.debugGetNextAtom();
            if (!checkOperator(a, ")")) {
                m_provider.setIndex(index);
                throw new AsinException("no )");
            }
        } else {
            m_provider.revertOne();
            tab = t;
            Tip tipEx1 = makeExpresie();
            tab = t;
            makeOpRel();
            tab = t;
            Tip tipEx2 = makeExpresie();
            if ((tipEx1.tip == TipSimbol.CHAR && tipEx2.tip == TipSimbol.CHAR)
                    || ((tipEx1.tip == TipSimbol.INT || tipEx1.tip == TipSimbol.REAL)
                    && (tipEx2.tip == TipSimbol.INT || tipEx2.tip == TipSimbol.REAL))) {
            } else {
                throw new AsinException("Tipuri incompatibile pentru expresii logice!");
            }
        }
    }

    private void makeOpRel() throws AsinException {
        int t = ++tab;
        printDebug("makeOpRel");

        Atom o = m_provider.debugGetNextAtom();
        if (!checkOperator(o, "<") && !checkOperator(o, ">") && !checkOperator(o, "<=") && !checkOperator(o, ">=") && !checkOperator(o, "=") && !checkOperator(o, "<>")) {
            m_provider.putUnusedAtom(o);
            throw new AsinException("no possibility");
        }
    }

    private void makeExprLogica2() throws AsinException {
        int t = ++tab;
        printDebug("makeExprLogica");

        boolean found = true;
        try {
            tab = t;
            makeOpLog();
        } catch (Exception e) {
            found = false;
        }
        if (!found) {
            return;
        }
        tab = t;
        makeExprRel();
        tab = t;
        makeExprLogica2();
    }

    private void makeOpLog() throws AsinException {
        int t = ++tab;
        printDebug("makeOpLog");

        Atom o = m_provider.debugGetNextAtom();
        if (!checkKeyword(o, Keyword.AND) && !checkKeyword(o, Keyword.OR)) {
            m_provider.putUnusedAtom(o);
            throw new AsinException("no possibility");
        }
    }

    private void makeInstrAtrib() throws AsinException {
        int t = ++tab;
        printDebug("makeInstrAtrib");
        tab = t;
        Tip tipVariabila = makeVariabila();
        Atom o = m_provider.debugGetNextAtom();
        if (!checkOperator(o, ":=")) {
            m_provider.revertOne();
            throw new AsinException("no :=");
        }
        tab = t;
        Tip tipExpresie = makeExpresie();
        if (tipVariabila.tip != tipExpresie.tip) {
            if (tipVariabila.tip == TipSimbol.CHAR || tipExpresie.tip == TipSimbol.CHAR || tipVariabila.tip == TipSimbol.INT) {
                throw new AsinException("inconvertible " + tipVariabila.tip + ":=" + tipExpresie.tip);
            }
        }
    }

    private Tip makeVariabila() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeVariabila");

        Atom a = m_provider.debugGetNextAtom();
        String numeIden = checkIdentifier(a);
        if (numeIden == null) {
            m_provider.setIndex(index);
            throw new AsinException("no identifier");
        }

        Tip tipNou = null;
        Atom a2 = m_provider.debugGetNextAtom();
        if (checkOperator(a2, "[")) {
            tab = t;
            Tip tipExpresie = makeExpresie();
            Atom op = m_provider.debugGetNextAtom();
            if (!checkOperator(op, "]")) {
                m_provider.setIndex(index);
                throw new AsinException("no ]");
            }
            int indexSimbol = m_tblSimbol.getIndex(numeIden);
            Simbol simbol = m_tblSimbol.getSimbol(indexSimbol);
            if (simbol.clasa != ClsSimbol.TABLOU) {
                throw new AsinException("Identifier is not an array!");
            } else {
                if (tipExpresie.tip != TipSimbol.INT) {
                    throw new AsinException("Array index is not an integer!");
                } else {
                    tipNou.tip = simbol.tip;
                }
            }
            return tipNou;
        } else if (checkDelimitator(a2, ".")) {
            Atom iden = m_provider.debugGetNextAtom();
            String numeComp = checkIdentifier(iden);
            if (numeComp == null) {
                m_provider.setIndex(index);
                throw new AsinException("no identifier");
            }
            tipNou = m_tblSimbol.isMemberOf(numeComp, numeIden);
            if (tipNou == null) {
                throw new AsinException("not a member!");
            }
            return tipNou;
        } else {
            m_provider.revertOne();
            tipNou = new Tip();
            int indexSimbol = m_tblSimbol.getIndex(numeIden);
            Simbol simbol = m_tblSimbol.getSimbol(indexSimbol);
            if (simbol.clasa == ClsSimbol.VARIABILA || simbol.clasa == ClsSimbol.CAMP_PARA) {
                tipNou.tip = simbol.tip;
            } else if (simbol.clasa == ClsSimbol.FUNCTIE) {
                if (!m_tblSimbol.isLastFunction(simbol)) {
                    throw new AsinException("Cannot call function!");
                } else {
                    tipNou.tip = simbol.tip;
                }
            }
            return tipNou;
        }
    }

    private Tip makeExpresie() throws AsinException {
        int t = ++tab;
        Tip tipNou;

        printDebug("makeExpresie");
        tab = t;
        tipNou = makeTermen();
        tab = t;
        tipNou = makeExpresie2(tipNou);
        tipNou.lvalue = TipValue.ADRESA;
        return tipNou;
    }

    private Tip makeTermen() throws AsinException {
        int t = ++tab;
        printDebug("makeTermen");
        tab = t;
        Tip tFactor = makeFactor();
        tab = t;
        return makeTermen2(tFactor);
    }

    private Tip makeTermen2(Tip tLast) throws AsinException {
        int t = ++tab;
        printDebug("makeTermen2 cu tip " + tLast.tip);

        OpMul op;
        try {
            tab = t;
            op = makeOpMul();
        } catch (Exception e) {
            return tLast;
        }
        tab = t;
        Tip tNext = makeFactor();
        tab = t;
        Tip tRez = new Tip();
        if (op == OpMul.DIV || op == OpMul.MOD) {
            if (tLast.tip != TipSimbol.INT || tNext.tip != TipSimbol.INT) {
                throw new AsinException("tipes are not int!");
            }
            tRez.tip = TipSimbol.INT;
        } else {
            if (tLast.tip == TipSimbol.CHAR || tNext.tip == TipSimbol.CHAR) {
                throw new AsinException("not char types");
            }
            if (op == OpMul.MULTIPLY && tLast.tip == TipSimbol.INT && tNext.tip == TipSimbol.INT) {
                tRez.tip = TipSimbol.INT;
            } else {
                tRez.tip = TipSimbol.REAL;
            }
        }
        return makeTermen2(tRez);
    }

    private Tip makeFactor() throws AsinException {
        int t = ++tab, index = m_provider.getCurrentIndex();
        printDebug("makeFactor");

        Tip tFactor = null;
        try {
            tab = t;
            tFactor = makeConstanta();
        } catch (AsinException ex) {
            debugException(ex);
        }
        if (tFactor != null) {
            return tFactor;
        }
        m_provider.setIndex(index);
        Atom a = m_provider.debugGetNextAtom();
        String numeIden;
        if (checkOperator(a, "(")) {
            tab = t;
            tFactor = makeExpresie();
            Atom op = m_provider.debugGetNextAtom();
            if (!checkOperator(op, ")")) {
                m_provider.setIndex(index);
                throw new AsinException("no )");
            }
            return tFactor;
        } else if ((numeIden = checkIdentifier(a)) != null) {
            Atom op = m_provider.debugGetNextAtom();
            if (checkOperator(op, "(")) {
                tab = t;
                ArrayList<Tip> tParam = makeListaExpresii();
                Atom op2 = m_provider.debugGetNextAtom();
                if (!checkOperator(op2, ")")) {
                    m_provider.setIndex(index);
                    throw new AsinException("no )");
                }
                Tip tSubprog = m_tblSimbol.checkSubprog(numeIden, tParam);
                if (tSubprog == null) {
                    throw new AsinException("subprogram not found!");
                }
                return tSubprog;
            } else if (checkDelimitator(op, ".")) {
                Atom at = m_provider.debugGetNextAtom();
                String numeComp = checkIdentifier(at);
                if (numeComp == null) {
                    m_provider.setIndex(index);
                    throw new AsinException("no identifier)");
                }
                Tip tCamp = m_tblSimbol.isMemberOf(numeComp, numeIden);
                if (tCamp == null) {
                    throw new AsinException("Not member of!");
                }
                return tCamp;
            } else if (checkOperator(op, "[")) {
                tab = t;
                Tip tIndex = makeExpresie();
                Atom op2 = m_provider.debugGetNextAtom();
                if (!checkOperator(op2, "]")) {
                    m_provider.setIndex(index);
                    throw new AsinException("no ]");
                }
                if (tIndex.tip != TipSimbol.INT) {
                    throw new AsinException("Index not int");
                }
                int indexSimbol = m_tblSimbol.getIndex(numeIden);
                Simbol simbol = m_tblSimbol.getSimbol(indexSimbol);
                if (simbol.clasa != ClsSimbol.TABLOU) {
                    throw new AsinException("Not a table!s");
                }
                Tip tTbl = new Tip();
                tTbl.tip = simbol.tip;
                tTbl.lvalue = TipValue.ADRESA;
                return tTbl;
            } else {
                m_provider.revertOne();
                int indexSimbol = m_tblSimbol.getIndex(numeIden);
                Simbol simbol = m_tblSimbol.getSimbol(indexSimbol);
                Tip tIden = new Tip();
                if (simbol.clasa == ClsSimbol.CONSTANTA) {
                    Tip tConst = m_tblSimbol.getConstVal(simbol);
                    tIden.tip = tConst.tip;
                    tIden.valoare = tConst.valoare;
                    tIden.lvalue = TipValue.VALOARE;
                    return tIden;
                } else if (simbol.clasa == ClsSimbol.VARIABILA) {
                    tIden.tip = simbol.tip;
                    tIden.lvalue = TipValue.ADRESA;
                    return tIden;
                } else if (simbol.clasa == ClsSimbol.CAMP_PARA) {
                    tIden.tip = simbol.tip;
                    tIden.lvalue = TipValue.VALOARE;
                    return tIden;
                } else if (simbol.clasa == ClsSimbol.FUNCTIE) {
                    if (simbol.nr_par != 0) {
                        throw new AsinException("nu sunt parametrii!");
                    }
                    tIden.tip = simbol.tip;
                    tIden.lvalue = TipValue.VALOARE;
                    return tIden;
                } else {
                    throw new AsinException("Simbolul " + simbol.nume + " nu poate fi factor!");
                }
            }
        } else {
            m_provider.setIndex(index);
            throw new AsinException("no possibility 2");
        }
    }

    private ArrayList<Tip> makeListaExpresii() throws AsinException {
        int t = ++tab;
        printDebug("makeListaExpresii");
        tab = t;
        ArrayList<Tip> tExpr = new ArrayList<>();
        tExpr.add(makeExpresie());
        tab = t;
        return makeListaExpresii2(tExpr);
    }

    private ArrayList<Tip> makeListaExpresii2(ArrayList<Tip> lista) throws AsinException {
        int t = ++tab;
        printDebug("makeListaExpresii2");

        Atom op = m_provider.debugGetNextAtom();
        if (!checkDelimitator(op, ",")) {
            m_provider.revertOne();
            return lista;
        }
        tab = t;
        lista.add(makeExpresie());
        tab = t;
        return makeListaExpresii2(lista);
    }

    private Tip makeExpresie2(Tip tLast) throws AsinException {
        int t = ++tab;
        printDebug("makeExpresie2 cu " + tLast.tip);

        try {
            tab = t;
            makeOpAd();
        } catch (Exception e) {
            return tLast;
        }
        tab = t;
        Tip tNext = makeTermen();
        tab = t;
        Tip tRez = new Tip();
        if (tLast.tip == TipSimbol.CHAR || tNext.tip == TipSimbol.CHAR) {
            throw new AsinException("tipuri char!");
        }
        if (tLast.tip == TipSimbol.INT && tNext.tip == TipSimbol.INT) {
            tRez.tip = TipSimbol.INT;
        } else {
            tRez.tip = TipSimbol.REAL;
        }
        return makeExpresie2(tRez);
    }

    private void makeListaInstr2() throws AsinException {
        int t = ++tab;
        printDebug("makeListaInstr2");

        Atom del = m_provider.debugGetNextAtom();
        if (!checkDelimitator(del, ";")) {
            m_provider.putUnusedAtom(del);
            return;
        }
        tab = t;
        makeInstr();
        tab = t;
        makeListaInstr2();
    }

    /*
     * private boolean makeInstrComp() throws AsinException { throw new
     * AsinException("makeInstrComp"); }
     */
    public static void main(String args[]) {
        FileProvider provider = new FileProvider("exemplu.txt");
        Analizator alex = new Analizator(provider);
        AtomProvider atomProvider = new AtomProvider(alex);
        AnalizatorSintactic asin = new AnalizatorSintactic(atomProvider);
        try {
            asin.makeProgram();
            asin.printTabelaSimboluri();
        } catch (AsinException e) {
            e.printStackTrace(System.out);




        }
    }

    public class AsinException extends Exception {

        public AsinException(String message) {
            super(message);
        }

        public AsinException(String message, Atom a) {
            super(message + ":" + a.toString());
        }
    }

    private boolean checkKeyword(Atom a, Keyword key) {
        if (a instanceof CuvantCheie) {
            return ((CuvantCheie) a).m_keyword == key;
        }
        return false;
    }

    private boolean checkDelimitator(Atom a, String cmp) {
        if (a instanceof Delimitator) {
            return ((Delimitator) a).m_value.equals(cmp);
        }
        return false;
    }

    private boolean checkOperator(Atom a, String cmp) {
        if (a instanceof Operator) {
            return ((Operator) a).m_value.equals(cmp);
        }
        return false;
    }

    public String checkIdentifier(Atom a) {
        if (a instanceof Identificator) {
            return ((Identificator) a).getNume();
        }
        if (a instanceof Caracter) {
            return ((Caracter) a).value + "";
        }
        return null;
    }
}
